package fun.stgoder.dev.listener.sdk;

import cn.hutool.core.util.StrUtil;
import com.sun.jna.*;
import com.sun.jna.ptr.IntByReference;
import fun.stgoder.dev.listener.common.BitUtil;
import fun.stgoder.dev.listener.common.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.InetAddress;
import java.util.BitSet;

public class HCNetSDKWrapper {
    private Logger logger = LoggerFactory.getLogger(HCNetSDKWrapper.class);

    private boolean initSuccess;
    private String ip;
    private Integer port;
    private String username;
    private String password;

    private HCNetSDK hCNetSDK = HCNetSDKWrapper.load();

    private NativeLong lUserID;
    private NativeLong lAlarmHandle;
    private NativeLong lListenHandle;

    private NativeLong m_lUploadHandle;
    private NativeLong m_UploadStatus;

    private NativeLong lChannel;

    private FMSGCallBack_V31 fMSFCallBack_V31 = new FMSGCallBack_V31();

    private NativeLong lVoiceHandle;

    private NativeLong lVoiceComHandle;

    private FVoiceDataCallBack_MR_V30 fVoiceDataCallBack_MR_V30 = new FVoiceDataCallBack_MR_V30();

    private FVoiceDataCallBack_V30 fVoiceDataCallBack_V30 = new FVoiceDataCallBack_V30();

    public static HCNetSDK load() {
        HCNetSDK hCNetSDK = null;
        if (Platform.isWindows()) {
            hCNetSDK = (HCNetSDK) Native.loadLibrary(Constants.HCNETSDK_PATH + File.separator + "HCNetSDK.dll",
                    HCNetSDK.class);
        }
        if (Platform.isLinux()) {
            hCNetSDK = (HCNetSDK) Native.loadLibrary(Constants.HCNETSDK_PATH + File.separator + "libhcnetsdk.so",
                    HCNetSDK.class);
        }
        return hCNetSDK;
    }

    public HCNetSDKWrapper(String ip, Integer port, String username, String password) {
        this.ip = ip;
        this.port = port;
        this.username = username;
        this.password = password;
    }

    public boolean isInitSuccess() {
        return initSuccess;
    }

    public void setInitSuccess(boolean initSuccess) {
        this.initSuccess = initSuccess;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public HCNetSDKWrapper init() throws Exception {
        lUserID = new NativeLong(-1);
        lAlarmHandle = new NativeLong(-1);
        lListenHandle = new NativeLong(-1);

        m_lUploadHandle = new NativeLong(-1);
        m_UploadStatus = new NativeLong(-1);

        lChannel = new NativeLong(-1);

        lVoiceHandle = new NativeLong(-1);
        lVoiceComHandle = new NativeLong(-1);

        boolean success = hCNetSDK.NET_DVR_Init();
        if (!success)
            throw new Exception("hcnetsdk init err");
        if (Constants.TEST_MODE)
            logger.info("init success");
        return this;
    }


    public HCNetSDKWrapper login_V40() throws Exception {
        HCNetSDK.NET_DVR_DEVICEINFO_V30 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();
        lUserID = hCNetSDK.NET_DVR_Login_V30(ip, port.shortValue(), username, password, m_strDeviceInfo);
        if (lUserID.intValue() == -1)
            throw new Exception("login_V40 err: " + getLastError());
        if (Constants.TEST_MODE)
            logger.info("login_V40 success");
        return this;
    }

    public HCNetSDKWrapper logout() throws Exception {
        boolean success = hCNetSDK.NET_DVR_Logout(lUserID);
        if (!success)
            throw new Exception("logout err: " + getLastError());
        if (Constants.TEST_MODE)
            logger.info("logout success");
        return this;
    }

    public HCNetSDKWrapper setDVRMessageCallBack_V31() throws Exception {
        if (!hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(fMSFCallBack_V31, null))
            throw new Exception("setDVRMessageCallBack_V31 err: " + getLastError());
        if (Constants.TEST_MODE)
            logger.info("setDVRMessageCallBack_V31 success");
        return this;
    }

    public HCNetSDKWrapper setupAlarmChan_V41() throws Exception {
        if (lUserID.intValue() == -1)
            throw new Exception("not login err: " + getLastError());
        if (lAlarmHandle.intValue() < 0) {
            HCNetSDK.NET_DVR_SETUPALARM_PARAM m_strAlarmInfo = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
            m_strAlarmInfo.dwSize = m_strAlarmInfo.size();
            m_strAlarmInfo.byLevel = 1;
            m_strAlarmInfo.byAlarmInfoType = 1;
            m_strAlarmInfo.byDeployType = 1;

            BitSet set = new BitSet(8);
            set.set(1);
            set.set(1);
            set.set(1);
            byte[] bytes = BitUtil.bitSet2ByteArray(set);
            byte byAlarmTypeURL = bytes[0];

            m_strAlarmInfo.byAlarmTypeURL = byAlarmTypeURL;
            m_strAlarmInfo.write();
            lAlarmHandle = hCNetSDK.NET_DVR_SetupAlarmChan_V41(lUserID, m_strAlarmInfo);
            if (lAlarmHandle.intValue() == -1) {
                throw new Exception("setupAlarmChan_V41 err: " + getLastError());
            }
        }
        if (Constants.TEST_MODE)
            logger.info("setupAlarmChan_V41 success");
        return this;
    }

    public HCNetSDKWrapper setupAlarmChan_V41_car() throws Exception {
        if (lUserID.intValue() == -1)
            throw new Exception("not login err: " + getLastError());
        if (lAlarmHandle.intValue() < 0) {
            HCNetSDK.NET_DVR_SETUPALARM_PARAM m_strAlarmInfo = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
            m_strAlarmInfo.dwSize = m_strAlarmInfo.size();
            m_strAlarmInfo.byLevel = 1;
            m_strAlarmInfo.byAlarmInfoType = 1;
            m_strAlarmInfo.byDeployType = 1;

            BitSet set = new BitSet(8);
            set.set(1);
            byte[] bytes = BitUtil.bitSet2ByteArray(set);
            byte byCustomCtrl = bytes[0];
            m_strAlarmInfo.byCustomCtrl = byCustomCtrl;

            m_strAlarmInfo.write();
            lAlarmHandle = hCNetSDK.NET_DVR_SetupAlarmChan_V41(lUserID, m_strAlarmInfo);
            if (lAlarmHandle.intValue() == -1) {
                throw new Exception("setupAlarmChan_V41 err: " + getLastError());
            }
        }
        if (Constants.TEST_MODE)
            logger.info("setupAlarmChan_V41 success");
        return this;
    }

    public HCNetSDKWrapper startAlarmListen_V30(short port) throws Exception {
        if (lAlarmHandle.intValue() >= 0) {
            FMSGCallBack fMSFCallBack = new FMSGCallBack();
            lListenHandle = hCNetSDK.NET_DVR_StartListen_V30(InetAddress.getLocalHost().getHostAddress(), port,
                    fMSFCallBack, null);
            if (lListenHandle.intValue() < 0) {
                throw new Exception("startAlarmListen_V30 err: " + getLastError());
            } else {
                if (Constants.TEST_MODE)
                    logger.info("startAlarmListen_V30 at " + InetAddress.getLocalHost().getHostAddress() + ":" + port
                            + " success");
            }
        }
        return this;
    }

    public HCNetSDKWrapper closeAlarmChan_V30() throws Exception {
        boolean success = hCNetSDK.NET_DVR_CloseAlarmChan_V30(lAlarmHandle);
        if (!success)
            throw new Exception("closeAlarmChan_V30 err: " + getLastError());
        if (Constants.TEST_MODE)
            logger.info("closeAlarmChan_V30 success");
        return this;
    }

    public HCNetSDKWrapper cleanup() throws Exception {
        boolean success = hCNetSDK.NET_DVR_Cleanup();
        if (!success)
            throw new Exception("cleanup err: " + getLastError());
        if (Constants.TEST_MODE)
            logger.info("cleanup success");
        return this;
    }

    public int getLastError() throws Exception {
        int err = hCNetSDK.NET_DVR_GetLastError();
        return err;
    }

    public void NET_DVR_GetDVRConfig() {
        hCNetSDK.NET_DVR_GetDVRConfig(lUserID, 0, lChannel, null, 0, null);
    }


    public int lUserID() {
        return lUserID.intValue();
    }

    public int lAlarmHandle() {
        return lAlarmHandle.intValue();
    }

    /// Callback
    public class FMSGCallBack_V31 implements HCNetSDK.FMSGCallBack_V31 {
        @Override
        public boolean invoke(NativeLong lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen,
                              Pointer pUser) {
            handleMsg(lCommand, pAlarmer, pAlarmInfo, dwBufLen, pUser);
            return true;
        }
    }

    public class FMSGCallBack implements HCNetSDK.FMSGCallBack {
        public void invoke(NativeLong lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen,
                           Pointer pUser) {
            handleMsg(lCommand, pAlarmer, pAlarmInfo, dwBufLen, pUser);
        }
    }

    private void handleMsg(NativeLong lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen,
                           Pointer pUser) {

        int alarmType = lCommand.intValue();

        if (alarmType == HCNetSDK.COMM_UPLOAD_FACESNAP_RESULT) {
            long makeMsg0Start = System.currentTimeMillis();

            HCNetSDK.NET_VCA_FACESNAP_RESULT strFaceSnapInfo = new HCNetSDK.NET_VCA_FACESNAP_RESULT();
            strFaceSnapInfo.write();
            Pointer pFaceSnapInfo = strFaceSnapInfo.getPointer();
            pFaceSnapInfo.write(0, pAlarmInfo.getByteArray(0, strFaceSnapInfo.size()), 0, strFaceSnapInfo.size());
            strFaceSnapInfo.read();

            String cameraIp = new String(strFaceSnapInfo.struDevInfo.struDevIP.sIpV4).trim();
            if (Constants.TEST_MODE)
                logger.debug("cameraIp: " + cameraIp);
            if (StrUtil.isBlank(cameraIp))
                return;

            int dwFaceScore = strFaceSnapInfo.dwFaceScore;

            if (Constants.TEST_MODE)
                logger.debug("face score: " + dwFaceScore);

            if (dwFaceScore < Constants.FACE_SCORE) {
                if (Constants.TEST_MODE)
                    logger.debug("face score < " + Constants.FACE_SCORE + ", drop this snap");
                return;
            }

            FaceMsg msg = new FaceMsg();
            // file
            byte[] smallFileBytes = strFaceSnapInfo.pBuffer1.getByteArray(0, strFaceSnapInfo.dwFacePicLen);
            msg.setSmallFileBytes(smallFileBytes);
            msg.setTs(makeMsg0Start);
            msg.setCameraIp(cameraIp);
            msg.setFaceScore(dwFaceScore);
            msg.setEts(System.currentTimeMillis());

            FaceMsgExecutor.execute(new FaceMsgTask(msg));
        }

        if (alarmType == HCNetSDK.COMM_ITS_PLATE_RESULT) { // 交通抓拍结果(新报警信息)
            HCNetSDK.NET_ITS_PLATE_RESULT struItsPlateResult = new HCNetSDK.NET_ITS_PLATE_RESULT();
            struItsPlateResult.write();
            Pointer pItsPlateResult = struItsPlateResult.getPointer();
            pItsPlateResult.write(0, pAlarmInfo.getByteArray(0, struItsPlateResult.size()), 0, struItsPlateResult.size());
            struItsPlateResult.read();

            // 车型识别：0- 未知，1- 客车(大型)，2- 货车(大型)，3- 轿车(小型)，4- 面包车，5- 小货车，6- 行人，7- 二轮车，8- 三轮车，9- SUV/MPV，10- 中型客车，11- 机动车，12- 非机动车，13- 小型轿车，14- 微型轿车，15- 皮卡车
            int byVehicleType = struItsPlateResult.byVehicleType;

            HCNetSDK.NET_DVR_PLATE_INFO struPlateInfo = struItsPlateResult.struPlateInfo;
            String s = new String(struPlateInfo.sLicense);
            logger.info(s);
        }

    }

    public boolean uploadFile_V40(String FDID) throws Exception {
        HCNetSDK.NET_DVR_FACELIB_COND struInput = new HCNetSDK.NET_DVR_FACELIB_COND();
        struInput.dwSize = struInput.size();
        struInput.szFDID = FDID.getBytes();
        struInput.byConcurrent = 0;
        struInput.byCover = 1;
        struInput.byCustomFaceLibID = 0;
        struInput.write();

        Pointer lpInput = struInput.getPointer();

        NativeLong ret = hCNetSDK.NET_DVR_UploadFile_V40(lUserID, HCNetSDK.IMPORT_DATA_TO_FACELIB, lpInput,
                struInput.size(), null, null, 0);
        if (ret.longValue() == -1) {
            int code = hCNetSDK.NET_DVR_GetLastError();
            throw new Exception("NET_DVR_UploadFile_V40 err: " + code);
        } else {
            m_lUploadHandle = ret;
            return true;
        }
    }

    public void uploadSend(InputStream picfile, InputStream xmlfile) throws Exception {
        try {
            // int picdataLength = picfile.available();
            // int xmldataLength = xmlfile.available();
            int picdataLength = picfile.available();
            int xmldataLength = xmlfile.available();
            if (Constants.TEST_MODE)
                logger.debug("pic len: " + picdataLength);
            if (Constants.TEST_MODE)
                logger.debug("xml len: " + xmldataLength);

            if (picdataLength < 0 || xmldataLength < 0)
                throw new Exception("input file/xml dataSize < 0");

            HCNetSDK.BYTE_ARRAY ptrpicByte = new HCNetSDK.BYTE_ARRAY(picdataLength);
            HCNetSDK.BYTE_ARRAY ptrxmlByte = new HCNetSDK.BYTE_ARRAY(xmldataLength);

            picfile.read(ptrpicByte.byValue);
            xmlfile.read(ptrxmlByte.byValue);

            ptrpicByte.write();
            ptrxmlByte.write();

            HCNetSDK.NET_DVR_SEND_PARAM_IN struSendParam = new HCNetSDK.NET_DVR_SEND_PARAM_IN();
            struSendParam.pSendData = ptrpicByte.getPointer();
            struSendParam.dwSendDataLen = picdataLength;
            struSendParam.pSendAppendData = ptrxmlByte.getPointer();
            struSendParam.dwSendAppendDataLen = xmldataLength;

            if (struSendParam.pSendData == null || struSendParam.pSendAppendData == null
                    || struSendParam.dwSendDataLen == 0 || struSendParam.dwSendAppendDataLen == 0)
                throw new Exception("input file/xml data err");

            struSendParam.byPicType = 1;
            struSendParam.dwPicMangeNo = 0;
            struSendParam.write();

            NativeLong iRet = hCNetSDK.NET_DVR_UploadSend(m_lUploadHandle, struSendParam.getPointer(), null);
            if (iRet.longValue() < 0) {
                int code = hCNetSDK.NET_DVR_GetLastError();
                throw new Exception("NET_DVR_UploadSend err: " + code);
            } else {
                if (Constants.TEST_MODE)
                    logger.debug("NET_DVR_UploadSend success");
                if (Constants.TEST_MODE)
                    logger.debug("dwSendDataLen =" + struSendParam.dwSendDataLen);
                if (Constants.TEST_MODE)
                    logger.debug("dwSendAppendDataLen =" + struSendParam.dwSendAppendDataLen);
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (picfile != null) {
                picfile.close();
            }
            if (xmlfile != null) {
                xmlfile.close();
            }
        }
    }

    public NativeLong getUploadState() {
        IntByReference pInt = new IntByReference(0);
        m_UploadStatus = hCNetSDK.NET_DVR_GetUploadState(m_lUploadHandle, pInt);
        if (m_UploadStatus.longValue() == -1) {
            if (Constants.TEST_MODE)
                logger.debug("NET_DVR_GetUploadState fail,error=" + hCNetSDK.NET_DVR_GetLastError());
        } else if (m_UploadStatus.longValue() == 2) {
            if (Constants.TEST_MODE)
                logger.debug("is uploading!!!! progress = " + pInt.getValue());
        } else if (m_UploadStatus.longValue() == 1) {
            if (Constants.TEST_MODE)
                logger.debug("progress = " + pInt.getValue());
            if (Constants.TEST_MODE)
                logger.debug("Uploading Succ!!!!!");
        } else {
            if (Constants.TEST_MODE)
                logger.debug("NET_DVR_GetUploadState fail  m_UploadStatus=" + m_UploadStatus);
            if (Constants.TEST_MODE)
                logger.debug("NET_DVR_GetUploadState fail,error=" + hCNetSDK.NET_DVR_GetLastError());
        }
        return m_UploadStatus;
    }

    public String upload(String FDID, InputStream picfile, InputStream xmlfile) {
        String m_picID = null;
        try {
            uploadFile_V40(FDID);
            uploadSend(picfile, xmlfile);
            while (true) {
                if (-1 == m_lUploadHandle.longValue()) {
                    return null;
                }
                m_UploadStatus = getUploadState();
                if (m_UploadStatus.longValue() == 1) {
                    HCNetSDK.NET_DVR_UPLOAD_FILE_RET struPicRet = new HCNetSDK.NET_DVR_UPLOAD_FILE_RET();
                    struPicRet.write();
                    Pointer lpPic = struPicRet.getPointer();
                    boolean bRet = hCNetSDK.NET_DVR_GetUploadResult(m_lUploadHandle, lpPic, struPicRet.size());
                    if (!bRet) {
                        if (Constants.TEST_MODE)
                            logger.debug("NET_DVR_GetUploadResult failed with:" + hCNetSDK.NET_DVR_GetLastError());
                    } else {
                        if (Constants.TEST_MODE)
                            logger.debug("NET_DVR_GetUploadResult succ");
                        struPicRet.read();
                        m_picID = StrUtil.trim(new String(struPicRet.sUrl));
                        if (Constants.TEST_MODE)
                            logger.debug("PicID:" + m_picID);
                        return m_picID;
                    }

                    if (hCNetSDK.NET_DVR_UploadClose(m_lUploadHandle)) {
                        m_lUploadHandle.setValue(-1);
                    }
                } else if (m_UploadStatus.longValue() >= 3 || m_UploadStatus.longValue() == -1) {
                    if (Constants.TEST_MODE)
                        logger.debug("m_UploadStatus = " + m_UploadStatus);
                    hCNetSDK.NET_DVR_UploadClose(m_lUploadHandle);
                    m_lUploadHandle.setValue(-1);
                    break;
                }
            }
        } catch (Exception e) {
            System.err.println("sdk upload err: " + e.getMessage());
        } finally {
            hCNetSDK.NET_DVR_UploadClose(m_lUploadHandle);
        }
        return m_picID;
    }


    public boolean test() throws Exception {
        Pointer pInBuffer = new Memory(320);
        Pointer pOutBuffer = new Memory(160);

        byte[] inbuf = new byte[320];
        byte[] outbuf = new byte[160];

        try (InputStream input = new FileInputStream("C:\\Users\\Administrator\\Desktop\\8k.pcm");
             OutputStream output = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\test2.711")) {
            int len = 0;
            while ((len = input.read(inbuf)) != -1) {

                // write into in buffer
                pInBuffer.write(0, inbuf, 0, len);

                boolean ret = hCNetSDK.NET_DVR_EncodeG711Frame(0, pInBuffer, pOutBuffer);
                if (!ret) {
                    int code = getLastError();
                    throw new Exception("NET_DVR_EncodeG711Frame err: " + code);
                }

                // read from out buffer
                pOutBuffer.read(0, outbuf, 0, 160);
                output.write(outbuf);
            }
        }

        return true;
    }

    public boolean NET_DVR_GetSTDConfig(int dwCommand, HCNetSDK.LPNET_DVR_STD_CONFIG lpConfigParam) throws Exception {
        boolean ret = hCNetSDK.NET_DVR_GetSTDConfig(lUserID, dwCommand, lpConfigParam);
        if (!ret) {
            int code = getLastError();
            if (Constants.TEST_MODE)
                System.err.println("err: " + code);
        }
        return ret;
    }

    public boolean NET_DVR_SetSTDConfig(HCNetSDK.LPNET_DVR_STD_CONFIG lpConfigParam) throws Exception {
        boolean ret = hCNetSDK.NET_DVR_SetSTDConfig(lUserID, HCNetSDK.NET_DVR_SET_SUPPLEMENTLIGHT, lpConfigParam);
        if (!ret) {
            int code = getLastError();
            if (Constants.TEST_MODE)
                System.err.println("err: " + code);
        }
        return ret;
    }

    public boolean getLightupConfig() throws Exception {
        HCNetSDK.LPNET_DVR_STD_CONFIG lpConfigParam = new HCNetSDK.LPNET_DVR_STD_CONFIG();
        Pointer lpCondBuffer = new Memory(4);
        byte[] lightno = new byte[4];
        lightno[0] = 1 >> 0;
        lightno[1] = 1 >> 8;
        lightno[2] = 1 >> 16;
        lightno[3] = 1 >> 24;
        lpCondBuffer.write(0, lightno, 0, 4);

        lpConfigParam.lpCondBuffer = lpCondBuffer;
        lpConfigParam.dwCondSize = 4;

        lpConfigParam.lpInBuffer = null;
        lpConfigParam.dwInSize = 0;

        Pointer lpOutBuffer = new Memory(284);
        lpConfigParam.lpOutBuffer = lpOutBuffer;
        lpConfigParam.dwOutSize = 284;

        Pointer lpStatusBuffer = new Memory(1024 * 10);
        lpConfigParam.lpStatusBuffer = lpStatusBuffer;
        lpConfigParam.dwStatusSize = 1024 * 10;

        lpConfigParam.lpXmlBuffer = null;
        lpConfigParam.dwXmlSize = 0;

        lpConfigParam.byDataType = 0;

        lpConfigParam.write();

        boolean ret = NET_DVR_GetSTDConfig(HCNetSDK.NET_DVR_GET_SUPPLEMENTLIGHT, lpConfigParam);

        byte[] byteArray = lpOutBuffer.getByteArray(0, 284);
        if (Constants.TEST_MODE)
            logger.debug("a" + new String(byteArray));

        byte[] lpStatusBufferBytes = lpStatusBuffer.getByteArray(0, 1024 * 10);
        if (Constants.TEST_MODE)
            logger.debug(new String(lpStatusBufferBytes));

        return ret;
    }

    public boolean lightup(boolean lightup, int brightness) throws Exception {
        HCNetSDK.LPNET_DVR_STD_CONFIG lpConfigParam = new HCNetSDK.LPNET_DVR_STD_CONFIG();
        Pointer lpCondBuffer = new Memory(4);
        byte[] lightno = new byte[4];
        lightno[0] = 1 >> 0;
        lightno[1] = 1 >> 8;
        lightno[2] = 1 >> 16;
        lightno[3] = 1 >> 24;
        lpCondBuffer.write(0, lightno, 0, 4);
        lpConfigParam.lpCondBuffer = lpCondBuffer;
        lpConfigParam.dwCondSize = 4;

        HCNetSDK.NET_DVR_BUILTIN_SUPPLEMENTLIGHT light = new HCNetSDK.NET_DVR_BUILTIN_SUPPLEMENTLIGHT();
        light.dwSize = light.size();
        light.byMode = 3;
        light.byBrightnessLimit = (byte) brightness;
        HCNetSDK.NET_DVR_SCHEDULE_DAYTIME struSchedTime = new HCNetSDK.NET_DVR_SCHEDULE_DAYTIME();
        HCNetSDK.NET_DVR_DAYTIME struStartTime = new HCNetSDK.NET_DVR_DAYTIME();
        struStartTime.byHour = 0;
        struStartTime.byMinute = 0;
        struStartTime.bySecond = 0;
        struStartTime.wMilliSecond = 500;
        struStartTime.byRes = 0;
        struStartTime.write();
        struSchedTime.struStartTime = struStartTime;
        HCNetSDK.NET_DVR_DAYTIME struStopTime = new HCNetSDK.NET_DVR_DAYTIME();
        struStopTime.byHour = 23;
        struStopTime.byMinute = 59;
        struStopTime.bySecond = 59;
        struStopTime.wMilliSecond = 500;
        struStopTime.byRes = 0;
        struStopTime.write();
        struSchedTime.struStopTime = struStopTime;
        struSchedTime.write();
        light.struSchedTime = struSchedTime;
        light.write();

        lpConfigParam.lpInBuffer = light.getPointer();
        lpConfigParam.dwInSize = light.size();

        lpConfigParam.lpOutBuffer = null;
        lpConfigParam.dwOutSize = 0;

        Pointer lpStatusBuffer = new Memory(1024 * 10);
        lpConfigParam.lpStatusBuffer = lpStatusBuffer;
        lpConfigParam.dwStatusSize = 1024 * 10;

        lpConfigParam.lpXmlBuffer = null;
        lpConfigParam.dwXmlSize = 0;

        lpConfigParam.byDataType = 0;

        lpConfigParam.write();

        boolean ret = NET_DVR_SetSTDConfig(lpConfigParam);

        byte[] lpStatusBufferBytes = lpStatusBuffer.getByteArray(0, 1024 * 10);
        if (Constants.TEST_MODE)
            logger.debug(new String(lpStatusBufferBytes));

        return ret;
    }

    public class FVoiceDataCallBack_MR_V30 implements HCNetSDK.FVoiceDataCallBack_MR_V30 {

        @Override
        public void invoke(NativeLong lVoiceComHandle, String pRecvDataBuffer, int dwBufSize, byte byAudioFlag,
                           String pUser) {

        }

    }

    public void NET_DVR_StartVoiceCom_MR_V30() throws Exception {
        lVoiceHandle = hCNetSDK.NET_DVR_StartVoiceCom_MR_V30(lUserID, 1, fVoiceDataCallBack_MR_V30, null);
        if (lVoiceHandle.intValue() < 0) {
            int code = hCNetSDK.NET_DVR_GetLastError();
            throw new Exception("NET_DVR_StartVoiceCom_MR_V30 err: " + code);
        }
    }

    public byte[] NET_DVR_EncodeG711Frame(byte[] in) {
        if (in.length != 320) {
            System.err.println("NET_DVR_EncodeG711Frame in data length err: " + in.length);
            return null;
        }
        Pointer pInBuffer = new Memory(320);
        pInBuffer.write(0, in, 0, 320);
        Pointer pOutBuffer = new Memory(160);
        boolean ret = hCNetSDK.NET_DVR_EncodeG711Frame(0, pInBuffer, pOutBuffer);
        if (!ret) {
            int code = hCNetSDK.NET_DVR_GetLastError();
            System.err.println("NET_DVR_EncodeG711Frame err: " + code);
        }
        byte[] out = new byte[160];
        pOutBuffer.read(0, out, 0, 160);
        return out;
    }

    public void NET_DVR_VoiceComSendData(byte[] data) {
        if (data.length != 160) {
            System.err.println("NET_DVR_EncodeG711Frame in data length err: " + data.length);
            return;
        }
        boolean ret = hCNetSDK.NET_DVR_VoiceComSendData(lVoiceComHandle, new String(data), data.length);
        if (!ret) {
            int code = hCNetSDK.NET_DVR_GetLastError();
            System.err.println("NET_DVR_VoiceComSendData err: " + code);
        }
    }

    public void NET_DVR_StartVoiceCom_V30() throws Exception {
        lVoiceComHandle = hCNetSDK.NET_DVR_StartVoiceCom_V30(lUserID, 1, true, fVoiceDataCallBack_V30, null);
        if (lVoiceComHandle.intValue() < 0) {
            int code = hCNetSDK.NET_DVR_GetLastError();
            throw new Exception("NET_DVR_StartVoiceCom_V30 err: " + code);
        }
    }

    public class FVoiceDataCallBack_V30 implements HCNetSDK.FVoiceDataCallBack_V30 {

        @Override
        public void invoke(NativeLong lVoiceComHandle, String pRecvDataBuffer, int dwBufSize, byte byAudioFlag,
                           Pointer pUser) {
            if (Constants.TEST_MODE)
                logger.debug("recv voice");
        }

    }

    public static void main(String[] args) throws Exception {
        HCNetSDKWrapper sdk = new HCNetSDKWrapper("192.168.1.75", 8000, "admin", "a00000000");
        sdk.init();
        sdk.login_V40();


        //sdk.setDVRMessageCallBack_V31();
        //sdk.setupAlarmChan_V41_car();

        // test voice send
        sdk.NET_DVR_StartVoiceCom_MR_V30();
        File pcmFile = new File("C:\\Users\\stgoder\\Desktop\\test\\upload\\2");
        try (FileInputStream fileInputStream = new FileInputStream(pcmFile)) {
            byte[] buf = new byte[320];
            int i = -1;
            while ((i = fileInputStream.read(buf)) > 0) {
                if (i < 320) {
                    for (int j = i; j < 320; j++) {
                        buf[j] = 0;
                    }
                }

                byte[] out = sdk.NET_DVR_EncodeG711Frame(buf);
                sdk.NET_DVR_VoiceComSendData(out);
            }
        }
    }
}
